import sail from './index';
import {
    collection,
} from './behavior';
import { ComponentAttrs, GameBehavior, OriginBehavior } from './declare';

interface Data {
    bundle: string,
    originObjectID: string,
    x: number,
    y: number,
    width: number,
    height: number,
    zIndex: number,
}

class Variable {
    id: string;
    value: any;
}

const { ccclass, property } = cc._decorator;
@ccclass
export default class SailGameObject extends cc.Component {
    @property()
    public bundle: string; // 对应bundle的名字
    @property()
    public originObjectID: string;// 关联的对象id
    
    @property({ type: [Variable] })
    public variables: Variable[] = [];// {id:'1',value:11}
    @property()
    public behaviors: string[] = [];
    
    @property()
    get x() {
        return this.node.x;
    }
    
    set x(v) {
        this.node.x = v;
    }
    
    @property()
    get y() {
        return this.node.y;
    }
    
    set y(v) {
        this.node.y = v;
    }
    
    @property()
    get width() {
        return this.node.width;
    }
    
    set width(v) {
        this.node.width = v;
    }
    
    @property()
    get height() {
        return this.node.height;
    }
    
    set height(v) {
        this.node.height = v;
    }
    
    @property()
    get zIndex() {
        return this.node.zIndex;
    }
    
    set zIndex(v) {
        this.node.zIndex = v;
    }
    
    initVar(vars) {
        // 使用concat断开引用关系
        this.variables = [].concat(vars);
    }
    
    async init(data: SailGameObject) {
        // @ts-ignore
        const dependencies: Record<string, Record<string, any>> = data.dependencies;
        const allBundles = data.behaviors.concat(data.bundle);
        for (let i = 0; i < allBundles.length; i++) {
            const bundle = allBundles[i];
            const data = dependencies ? dependencies[bundle] : {};
            await this.initBundle(bundle, data || {});
        }
    }
    
    public async initBundle(bundleName: string, data: Record<string, any>) {
        if (!bundleName) {
            console.error(`无效的bundle: ${bundleName}`);
            return;
        }
        let entry: GameBehavior = sail.allBundles.find(el => el.bundle === bundleName);
        if (!entry) {
            entry = await sail.loadBundle(bundleName) as GameBehavior;
        }
        const node = this.node;
        if (node && node.isValid && entry && entry.component) {
            let script = node.getComponent(entry.component);
            if (!script) {
                script = node.addComponent(entry.component);
            }
            sail.setComponentProperties(script, data);
            return script;
        }
        return null;
    }
    
    private async addBehavior(bundleName: string, data: any) {
        const script = await this.initBundle(bundleName, data);
        if (script) {
            if (!this.behaviors.find(el => el === bundleName)) {
                this.behaviors.push(bundleName);
            }
        }
    }
    
    async getBehaviorComponents(): Promise<Record<string, cc.Component>> {
        const map = {};
        for (let i = 0; i < this.behaviors.length; i++) {
            const behavior = this.behaviors[i];
            const bundleInfo = await sail.loadBundle(behavior);
            if (bundleInfo) {
                const script = this.node.getComponent(bundleInfo.component);
                if (script) {
                    map[bundleInfo.bundle] = script;
                }
            }
        }
        return map;
    }
    
    async removeBehavior(bundleName: string) {
        const ret = await this.getBehaviorComponents();
        for (let item in ret) {
            const comp = ret[item];
            if (item === bundleName) {
                this.node.removeComponent(comp);
                const idx = this.behaviors.findIndex(el => el === bundleName);
                this.behaviors.splice(idx, 1);
                return true;
            }
        }
        return false;
    }
    
    modifyVariable(id: string, value: any) {
        let ret = this.variables.find(el => el.id === id);
        if (ret) {
            ret.value = value;
        } else {
            this.variables.push({ id, value });
        }
    }
    
    async dumpBehaviorData(): Promise<Record<string, ComponentAttrs[]>> {
        const ret = await this.getBehaviorComponents();
        return collection(ret);
    }
    
    async setProperty(bundle: string, key: string, value: any) {
        const bundleInfo = await sail.loadBundle(bundle);
        if (bundleInfo) {
            const script = this.node.getComponent(bundleInfo.component);
            if (script && sail.hasProperty(script, key)
            ) {
                script[key] = value;
            } else {
                cc.log('未知的属性：', key);
            }
        }
    }
}